home *** CD-ROM | disk | FTP | other *** search
- ;;
- ;; aPLib compression library - the smaller the better :)
- ;;
- ;; NASM 16bit assembler depacker example
- ;;
- ;; Copyright (c) 1998-2000 by Joergen Ibsen / Jibz
- ;; All Rights Reserved
- ;;
- ;; -> 16bit by METALBRAIN (metalb@bart.us.es)
- ;;
-
- org 256
-
- cld ;Clear direction flag for safety
- mov ah,4ah ;Modify memory block size (on start,
- ; the .COM program is given all free
- ; memory, but this could be less than
- ; the needed amount (162K). As a nice
- ; side effect, we are freeing unused
- ; memory, but who cares under DOS?
- mov bh,41 ;Number of needed paragraphs
- ; (rounded up)
- int 33 ;Resize
- jnc not_error008 ;Continue if no error
- call final ;Exit with message below
- db "Not enough memory$"
- not_error008 mov si,129 ;Arguments from PSP start here
- mov di,testitnow ;This will be called quite a few times
- ; and later will be used to place
- ; variables
- space1 call di ;Parse...
- jz space1 ;Search for non-space
- dec si ;Found: here start infile name
- mov dx,si ;Keep it in DX
- space2 call di ;Keep parsing
- jnz space2 ;Till a space appears
- mov [si-1],dh ;Make infile ASCIIZ
- space3 call di
- jz space3 ;Now search a non-space again
- dec si ;Here start outfile name
- push si ;Keep it in stack
- space4 lodsb ;Final parse
- cmp al," "
- ja space4 ;Space or below means end of filename
- mov [si-1],dh ;Make ASCIIZ this one too
- mov ax,3d00h ;Function to open infile
- int 33 ;Open infile
- jnc not_error001 ;Continue if no error
- call final ;Exit with message below
- db "Can't open infile$"
- not_error001 stosw
- mov dx,tmpname
- xor cx,cx
- mov ah,3ch
- int 33 ;Create temporal outfile: "g ok$"
- jnc not_error007 ;Continue if no error
- call final ;Exit with message below
- db "Can't open temporal outfile$"
- not_error007 stosw ;Store temporal outfile handle
- xchg ax,dx ;And place it in DX
- xor ebx,ebx ;EBX=0
- pop si ;Pop outfile name address from stack
- mov bh,8 ;BX=inbuff
- mov esp,ebx ;Set stack before inbuff
- mov bx,es ;Segment
- add bh,8 ; +32K
- imul eax,ebx,byte 16 ;32 bit start of segment address+32K
- add eax,esp ;EAX=freemem 32 bit address
- push si ;Push again outfile name address
- push dx ;Also store temporal outfile handle
- mov dl,128 ;Reset bit counter in DL, and DX=0080h
- mov cl,3 ;Set EAX at freemem32, origin32 and
- rep stosd ; limit32
- add [di-2],byte 2 ;Now limit32=freemem32+128K
- add [di-7],dx ;Now origin32=freemem32+32K
- xchg eax,edi ;Set freemem32 at EDI
- mov esi,edi ;And ESI
- ;Starting point for DEPACK16
- push edi ;Store freemem32
- literal call getesi ;Copy a byte from [esi] to [edi]
- putedi_nexttag call putedi
- call newtest ;Here EAX=0
- jmp short nexttag ;Decode next tag bits...
-
- normalcodepair xchg ax,cx ;High part of distance in AX
- dec ax ;Subtract 1. Min value is 0
- shl eax,8 ;EAX=00dddd00h
- call getesi ;Fill distance in AL
- call getgamma ;Take gamma encoded ECX
- cmp eax,32000
- jae domatch_with_2inc ;Above 31999: ECX+=2
- cmp ah,5
- jae domatch_with_inc ; 1279<EAX<32000: ECX=+1
- cmp ax,byte 127
- ja domatch ;EAX<128: ECX+=2
- domatch_with_2inc
- inc ecx
- domatch_with_inc
- inc ecx
- domatch xchg eax,ebp ;Store EAX in EBP
- domatch_R0 mov eax,ebp ;Take EAX from last EBP
- domatch_continue
- ;Here EAX=match distance
- ; ECX=match lenght
- push esi ;Store current read pointer
- mov esi,edi
- sub esi,eax ;ESI=EDI-EAX > origin pointer
- cmp esi,[freemem32] ;Test for bad infile #1: Limit crossed
- jc near badinfile ;Exit if error
- repmovsb call dontread ;getesi without checking limit
- call putedi ;and with putedi completes the movsb
- mov ah,128 ;Here EAX=32768 (in case of writing
- call newtest ; data, update esi too)
- loop repmovsb,ecx ;Do it ecx times
- pop esi ;Recover read pointer
- nexttag call getbit ;Get a bit
- jnc literal ;0: literal, go for it
- xor ecx,ecx ;Clear ECX
- xor ax,ax ;and AX
- call getbit ;Get another bit
- jnc codepair ;10: codepair, go for it
- call getbit ;Get yet another one
- jnc shortmatch ;110: shortmatch
- inc cx ;CX=1
- mov al,16 ;Set marker bit
- getmorebits call getbit ;Get a bit
- adc al,al ;Set it in AL
- jnc getmorebits ;Do it till marker is out (4 times)
- jnz domatch_continue ; 111xxxx > continue, AL has distance
- jmp short putedi_nexttag ;1110000: Put a zero byte
-
- codepair call getgamma ;Get gamma encoded first part of
- ; distance in CX. Min value is 2
- dec cx ;\Subtract 2, if not zero then
- loop normalcodepair ;/continue with distance
- push word domatch_R0 ;Get gamma encoded lenght in ECX then
- ; jump to domatch_R0 (use last
- ; distance)
-
- getgamma inc cx ;First bit is always 1
- getgammaloop call getbit ;Get next bit
- adc ecx,ecx ;Put it in ECX
- call getbit ;Get gamma bit
- jc getgammaloop ;If it's 1, continue growing ECX
- ret
-
- shortmatch call getesi ;Get a byte
- shr ax,1 ;Distance = AL/2, Lenght in carry flag
- jz donedepacking ;If zero, end packing
- adc cx,cx ;Lenght = 1 or 0
- jmp short domatch_with_2inc ; Decode with lenght 2 or 3
-
- getbit add dl,dl ;Get a tag bit
- jnz stillbitsleft ;If zero, that bit was the marker, so
- ; we must read a new tag byte from
- xchg ax,dx ;\ the infile buffer
- call getesi ; >Emulate mov dl,[esi], inc esi
- xchg ax,dx ;/
- stc ;Carry flag is end marker
- adc dl,dl ;Get first bit and set marker
- stillbitsleft ret ;Return with bit read in flag C
-
- donedepacking pop esi ;ESI=freemem32
- pop bx ;Get outfile handle
- sub edi,esi ;And here finish DEPACK 16
- ;Now edi has the number of depacked
- ; bytes left to be written
- push ds ;Preserve data segment
- mov ch,080h ;Write using 32K chunks to enable
- ; the sign optimization
- mov dx,freemem ;Flush everything from here to end
- more cmp edi,ecx
- ja notlast ;If EDI > 32K, write 32K bytes
- mov cx,di ;If EDI < 32K, write EDI bytes
- notlast call writefile ;Write chunk
- mov ax,ds
- add ah,8
- mov ds,ax ;Advance 32K
-
- sub edi,ecx ;Update number of bytes to be written
- ja more ;Above zero, continue writing
- pop ds ;Recover data segment
- push ds
- pop es ;Set es=ds
- pop dx ;Get nameout
- call close_del ;Close temporal outfile and try to
- ; delete the file named with our
- ; outfile name, in case it exists
- jnc renameit ;If that file existed and was deleted,
- ; go ahead and rename the temporal one
- cmp al,5 ;If it didn't exist, rename it too
- jz error002b ;In case of Access denied, it must
- ; be that outfile was protected, so
- ; that's an error...
- renameit mov ah,56h
- mov di,dx
- mov dx,tmpname
- int 33 ;Rename temporal outfile to outfile
- jc error002 ;Can't open outfile
- push word noerr ;Final message
- final push ss
- pop ds ;Set a good data segment
- pop dx ;Get message offset
- final_dxok mov ah,9
- int 33 ;Show final message
- int 20h ;Exit program
- writefile mov ah,40h
- int 33 ;Write to temporal outfile
- jc error005 ;Can't write
- dec ax
- js error006 ;Disk is full
- ret
- error002b push word err002b ;Set appropiate message
- jmp short rub3 ;Exit erasing temporal file
- error002 push word err002 ;Set appropiate message
- jmp short rub4 ;Exit erasing temporal file
- error005 push word err005 ;Set appropiate message
- jmp short rub3 ;Exit erasing temporal file
- error006 push word err006 ;Set appropiate message
- rub3 mov dx,tmpname ;Temporal file name to be erased
- rub4 push word final ;Return point to exit with error
- close_del mov ah,3eh
- int 33 ;Close temporal outfile
- mov ah,41h
- int 33 ;Delete it
- ret
-
- getesi cmp esi,[freemem32] ; If esi is at freemem32, we must
- jnz dontread ;load 32k of compressed data
- pushad ;Keep all registers (32bit because
- mov ah,3fh ; DOS function may modify EAX!!!)
- mov bx,[handlein] ;Take infile handle
- mov cx,32768 ;Number of bytes
- mov dx,inbuff ;Place to read
- int 33 ;Read, AX=number of bytes read
- jc error003 ;If error, go to exit
- noerror003 dec ax ;Test for bad infile #2: 0 bytes read
- ; (a good infile will finish and won't
- ; ask for more data)
- jns noerror004 ;No error, continue
- badinfile push word err004 ;Set appropiate message
- jmp short error004
- error003 push word err003 ;Set appropiate message
- error004 mov bx,[handletmp] ;Get handle to close temporal file
- jmp short rub3 ;Exit erasing temporal file
- noerror004 popad ;Restore all registers
- sub esi,32768 ;esi at beginning of buffer again
- dontread push esi ;----->Emulates mov al,[esi] in 16 bit
- pop bx ; / code (as mov al,[esi] gives
- pop bx ; / a nasty fault)
- ror bx,4 ; /
- mov es,bx ; /
- mov al,[es:si] ;/
- inc esi ;Update read pointer
- ret
-
- newtest cmp edi,[limit32] ;Check if we've run out of memory
- jc endtest ;NO: end test
- pushad ;Keep registers
- mov dx,freemem
- mov cx,32768
- mov bx,[handletmp]
- call writefile ;Write 32K of data
- mov ecx,edi
- mov esi,[origin32]
- sub ecx,esi ;ECX=number of bytes to be moved
- mov edi,[freemem32] ;Output data will be moved 32K back
- otherrepmovsb call getesi ; \
- call putedi ; >Emulates rep movsb
- loop otherrepmovsb,ecx ;/
- popad ;Restore registers
- sub esi,eax ;Update read pointer (sub 32K if
- ; we are in the repmovsb loop)
- mov ah,128 ;EAX=32K
- sub edi,eax ;Update write pointer
- endtest ret
-
- putedi push edi ;----->Emulate mov [edi],al in 16 bit
- pop bx ; / code (as mov [edi],al gives
- pop bx ; / a nasty fault)
- ror bx,4 ; /
- mov es,bx ; /
- mov [es:di],al ;/
- inc edi ;Update write pointer
- xor eax,eax ;Clear EAX
- noerror000 ret
- testitnow lodsb ;Parse one byte
- cmp al,32 ;Is it space?
- jnc noerror000 ;If valid char (above 31), return
- call final ;Exit with message below
- db "Usage: DEPPACK infile outfile",13,10,10
- db "infile must be an aPPACKed file",13,10
- db "wildcards are not allowed",13,10,10
- db "DEPPACK v0.9 Copyright (c) 1998-2000 by METALBRAIN",13,10
- db "aPLib v0.26b Copyright (c) 1998-2000 by Jibz, All Rights Reserved$"
- err005 db "Can't write temporal outfile$"
- err002b db "Outfile is protected, so...",13,10
- err002 db "Can't open outfile$"
- err003 db "Can't read from infile$"
- err004 db "Bad infile$"
- err006 db "Disk full$"
- noerr db "Deppackin"
- tmpname db "g ok$",0
-
- handlein EQU testitnow
- handletmp EQU testitnow+2
- freemem32 EQU testitnow+4
- origin32 EQU testitnow+8
- limit32 EQU testitnow+12
- ;Stack is between program and 2048
- inbuff EQU 2048 ;Place for 32K infile reading buffer
- freemem EQU inbuff+32768
-